package runninbuddy;

import javax.microedition.location.Location;
import javax.microedition.location.LocationException;
import javax.microedition.location.LocationListener;
import javax.microedition.location.LocationProvider;

import net.rim.device.api.gps.BlackBerryCriteria;
import net.rim.device.api.gps.BlackBerryLocation;
import net.rim.device.api.gps.BlackBerryLocationProvider;
import net.rim.device.api.system.AccelerometerData;
import net.rim.device.api.system.AccelerometerSensor;
import net.rim.device.api.system.Application;

public class DataGrabber implements LocationListener, Runnable {

	private final DataCombiner dataCombiner;
	private final BlackBerryLocationProvider bbLocationProvider;
	private final AccelerometerSensor.Channel accChannel;
	private final int interval;
	private final int timeout;
	private final int maxAge;
	private volatile boolean alive;
	private long startTime;
	private int ticks;

	public DataGrabber(DataCombiner dataCombiner,
			BlackBerryCriteria bbCriteria, int interval, int timeout, int maxAge)
			throws LocationException {
		this.dataCombiner = dataCombiner;
		this.bbLocationProvider = (BlackBerryLocationProvider) BlackBerryLocationProvider
				.getInstance(bbCriteria);
		this.accChannel = AccelerometerSensor.openRawDataChannel(Application
				.getApplication());
		this.interval = interval;
		this.timeout = timeout;
		this.maxAge = maxAge;
		this.alive = true;
	}

	public void run() {
		bbLocationProvider.setLocationListener(this, interval, timeout, maxAge);
		pollAccData();
	}

	private void pollAccData() {
		startTime = System.currentTimeMillis();
		ticks = 0;
		int accInterval = (interval * 1000) >> 2;
		while (alive) {
			synchronized (accChannel) {
				if (accChannel.isOpen())
					onData(accChannel.getAccelerometerData());
				else
					continue;
			}
			int runningAverage = 0;
			int tmpAverage = (int) ((System.currentTimeMillis() - startTime))
					/ ++ticks;
			if (tmpAverage >= 0 && tmpAverage < accInterval)
				runningAverage = tmpAverage;
			try {
				Thread.sleep(accInterval - runningAverage);
			} catch (InterruptedException e) {
				System.err.println("DataGrabber.run: " + e.getMessage());
			}
		}
	}

	public void stop() {
		alive = false;
		if (bbLocationProvider != null) {
			bbLocationProvider.setLocationListener(null, 0, 0, 0);
			bbLocationProvider.reset();
		}
		if (accChannel != null) {
			accChannel.close();
		}
	}

	public void locationUpdated(LocationProvider provider, Location location) {
		dataCombiner.put((BlackBerryLocation) location);
	}

	public void providerStateChanged(LocationProvider provider, int newState) {
		// TODO Auto-generated method stub
	}

	public void onData(AccelerometerData accData) {
		dataCombiner.put(accData);
	}
}
